/*
 * Sphere.cpp
 *
 *  Created on: 31/05/2011
 *      Author: jorge
 */

#include "Sphere.h"
#include <GL/gl.h>
#include <cmath>

namespace shapes {

Sphere::Sphere(int slices, int stacks, double radix) {

	if (radix >= 0.0) {
		this->radix = radix;
	} else {
		this-> radix = 1.0;
	}

	if (stacks >= 2) {
		this->stacks = stacks;
	} else {
		this->stacks = 2;
	}

	if (slices >= 3) {
		this->slices = slices;
	} else {
		this->slices = 3;
	}

}

Sphere::Sphere() {

}

Sphere::~Sphere() {

}

void Sphere::setSlices(int slices) {

	if (slices >= 3) {
			this->slices = slices;
	}

}

void Sphere::setStacks(int stacks) {

	if (stacks >= 2) {
			this->stacks = stacks;
	}

}

void Sphere::setRadix(double radix) {

	if (radix >= 0.0) {
			this->radix = radix;
	}

}

double Sphere::getRadix() {
	return radix;
}

int Sphere::getSlices() {
	return slices;
}

int Sphere::getStacks() {
	return stacks;
}

void Sphere::draw() {
	const float PI = 3.141592654;

	if (radix <= 0.0f || stacks <= 1 || slices <= 2) {
		return;
	}

	float r = fabs(radix);

	float theta = 0.0f;
	float phi = 0.0f;
	int i, j;
	float thetaInc = PI / stacks;
	float phiInc = 2.0 * PI / slices;
	float x, y, z, s, t, nx, ny, nz;

	//Polo norte con un cap
	glBegin(GL_TRIANGLE_FAN);

		s = 0.5;
		t = 1.0;
		glTexCoord2f(s, t);

		nx = sin(theta) * cos(phi);
		nz = sin(theta) * sin(phi);
		ny = cos(theta);
		glNormal3f(nx, ny, nz);

		x = r * sin(theta) * cos(phi);
		z = r * sin(theta) * sin(phi);
		y = r * cos(theta);
		glVertex3f(x, y, z);

		theta = thetaInc;
		//Para conservar la orientacion CCW debemos recorrer
		//phi de 2 * PI a 0.0
		phi = 2.0 * PI;
		for (i = 0; i <= slices; i++) {

			s = (1.0 - (phi / (2.0 * PI)));
			t = (1.0 - (theta / PI));
			glTexCoord2f(s, t);

			nx = sin(theta) * cos(phi);
			nz = sin(theta) * sin(phi);
			ny = cos(theta);
			glNormal3f(nx, ny, nz);

			x = r * sin(theta) * cos(phi);
			z = r * sin(theta) * sin(phi);
			y = r * cos(theta);
			glVertex3f(x, y, z);

			phi -= phiInc;
		}
	glEnd();

	//Trazamos la parte central
	for (i = 1; i < (stacks - 1); i++) {
		//Para conservar la orientacion CCW debemos recorrer
		//phi de 2 * PI a 0.0
		phi = 2.0 * PI;
		glBegin(GL_QUAD_STRIP);
		for (j = 0; j <= slices; j++) {
			s = (1.0 - (phi / (2.0 * PI)));
			t = 1.0 - (theta / PI);
			glTexCoord2f(s, t);

			nx = sin(theta) * cos(phi);
			nz = sin(theta) * sin(phi);
			ny = cos(theta);
			glNormal3f(nx, ny, nz);

			x = r * sin(theta) * cos(phi);
			z = r * sin(theta) * sin(phi);
			y = r * cos(theta);
			glVertex3f(x, y, z);

			s = (1.0 - (phi / (2.0 * PI)));
			t = 1.0 - ((theta + thetaInc) / PI);
			glTexCoord2f(s, t);

			nx = sin(theta + thetaInc) * cos(phi);
			nz = sin(theta + thetaInc) * sin(phi);
			ny = cos(theta + thetaInc);
			glNormal3f(nx, ny, nz);

			x = r * sin(theta + thetaInc) * cos(phi);
			z = r * sin(theta + thetaInc) * sin(phi);
			y = r * cos(theta + thetaInc);
			glVertex3f(x, y, z);

			phi -= phiInc;
		}
		glEnd();
		theta += thetaInc;
	}


	//Trazamos el Polo sur con su cap
	//Para conservar la orientacion CCW debemos recorrer
	//phi de 0.0 a 2.0 * PI (al contrario del polo norte)
	phi = 0.0;
	glBegin(GL_TRIANGLE_FAN);
		s = 0.5;
		t = 0.0;
		glTexCoord2f(s, t);

		nx = sin(PI) * cos(0.0);
		nz = sin(PI) * sin(0.0);
		ny = cos(PI);
		glNormal3f(nx, ny, nz);

		x = r * sin(PI) * cos(0.0);
		z = r * sin(PI) * sin(0.0);
		y = r * cos(PI);
		glVertex3f(x, y, z);

		for (i = 0; i <= slices; i++) {
			s = (1.0 - (phi / (2.0 * PI)));
			t = 1.0 - (theta / PI);
			glTexCoord2f(s, t);

			nx = sin(theta) * cos(phi);
			nz = sin(theta) * sin(phi);
			ny = cos(theta);
			glNormal3f(nx, ny, nz);

			x = radix * sin(theta) * cos(phi);
			z = radix * sin(theta) * sin(phi);
			y = radix * cos(theta);
			glVertex3f(x, y, z);

			phi += phiInc;
		}
	glEnd();
}

}
